#ifndef __INC_ENDIANFREE_H
#define __INC_ENDIANFREE_H

/*
 *	Call endian free function when
 *		1. Read/write packet content.
 *		2. Before write integer to IO.
 *		3. After read integer from IO.
*/

//
// Byte Swapping routine.
//
#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN
// Convert data
#define EF1Byte(_val)				((u1Byte)(_val))
#define EF2Byte(_val)				((u2Byte)(_val))
#define EF4Byte(_val)				((u4Byte)(_val))

#else
// Convert data
#define EF1Byte(_val)				((u1Byte)(_val))
#define EF2Byte(_val)				(	((((u2Byte)(_val))&0x00ff)<<8)	|			\
									((((u2Byte)(_val))&0xff00)>>8)	)
#define EF4Byte(_val)				(	((((u4Byte)(_val))&0x000000ff)<<24)	|		\
									((((u4Byte)(_val))&0x0000ff00)<<8)	|		\
									((((u4Byte)(_val))&0x00ff0000)>>8)	|		\
									((((u4Byte)(_val))&0xff000000)>>24)	)

#endif

//
// Read LE format data from memory
//
#define ReadEF1Byte(_ptr)		EF1Byte(*((pu1Byte)(_ptr)))
#define ReadEF2Byte(_ptr)			EF2Byte(*((UNALIGNED pu2Byte)(_ptr)))
#define ReadEF4Byte(_ptr)			EF4Byte(*( (UNALIGNED pu4Byte)(_ptr)))

//
// Write LE data to memory
//
#define WriteEF1Byte(_ptr, _val)	(*((pu1Byte)(_ptr)))=EF1Byte(_val)
#define WriteEF2Byte(_ptr, _val)	(*((UNALIGNED pu2Byte)(_ptr)))=EF2Byte(_val)
#define WriteEF4Byte(_ptr, _val)	(*((UNALIGNED pu4Byte)(_ptr)))=EF4Byte(_val)									

//
// Convert Host system specific byte ording (litten or big endia) to Network byte ording (big endian). 
// 20060507, by rcnjko.
//
#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN
	#define H2N1BYTE(_val)	((u1Byte)(_val))
	#define H2N2BYTE(_val)	(((((u2Byte)(_val))&0x00ff)<<8)	|	\
							 ((((u2Byte)(_val))&0xff00)>>8)	)
	#define H2N4BYTE(_val)	(((((u4Byte)(_val))&0x000000ff)<<24)|	\
							 ((((u4Byte)(_val))&0x0000ff00)<<8)	|	\
							 ((((u4Byte)(_val))&0x00ff0000)>>8)	|	\
							 ((((u4Byte)(_val))&0xff000000)>>24))
#else
	#define H2N1BYTE(_val)				((u1Byte)(_val))
	#define H2N2BYTE(_val)				((u2Byte)(_val))
	#define H2N4BYTE(_val)				((u4Byte)(_val))
#endif

// Read/Write Host system specific byte ording (litten or big endia) from/to Network byte ording (big endian). 
// By Bruce, 2012-03-07.
#define	WriteH2N1BYTE(_ptr, _val)	(*((pu1Byte)(_ptr)))= H2N1BYTE(_val)
#define	WriteH2N2BYTE(_ptr, _val)	(*((UNALIGNED pu2Byte)(_ptr)))= H2N2BYTE(_val)
#define	WriteH2N4BYTE(_ptr, _val)	(*((UNALIGNED pu4Byte)(_ptr)))= H2N4BYTE(_val)

#define ReadH2N1BYTE(_ptr)			H2N1BYTE(*((pu1Byte)(_ptr)))
#define ReadH2N2BYTE(_ptr)			H2N2BYTE(*((UNALIGNED pu2Byte)(_ptr)))
#define ReadH2N4BYTE(_ptr)			H2N4BYTE(*( (UNALIGNED pu4Byte)(_ptr)))

#define	WriteN2H1BYTE(_ptr, _val)	(*((pu1Byte)(_ptr)))= N2H1BYTE(_val)
#define	WriteN2H2BYTE(_ptr, _val)	(*((UNALIGNED pu2Byte)(_ptr)))= N2H2BYTE(_val)
#define	WriteN2H4BYTE(_ptr, _val)	(*((UNALIGNED pu4Byte)(_ptr)))= N2H4BYTE(_val)

#define ReadN2H1BYTE(_ptr)			N2H1BYTE(*((pu1Byte)(_ptr)))
#define ReadN2H2BYTE(_ptr)			N2H2BYTE(*((UNALIGNED pu2Byte)(_ptr)))
#define ReadN2H4BYTE(_ptr)			N2H4BYTE(*( (UNALIGNED pu4Byte)(_ptr)))

//
// Convert from (TCP/IP or 802.3)Network byte ording (big endian) to Host system specific byte ording (litten or big endia).
// 20060507, by rcnjko.
//
#if BYTE_ORDER == __MACHINE_LITTLE_ENDIAN
	#define N2H1BYTE(_val)	((u1Byte)(_val))
	#define N2H2BYTE(_val)	(((((u2Byte)(_val))&0x00ff)<<8)	|	\
							 ((((u2Byte)(_val))&0xff00)>>8)	)
	#define N2H4BYTE(_val)	(((((u4Byte)(_val))&0x000000ff)<<24)|	\
							 ((((u4Byte)(_val))&0x0000ff00)<<8)	|	\
							 ((((u4Byte)(_val))&0x00ff0000)>>8)	|	\
							 ((((u4Byte)(_val))&0xff000000)>>24))
#else
	#define N2H1BYTE(_val)				((u1Byte)(_val))
	#define N2H2BYTE(_val)				((u2Byte)(_val))
	#define N2H4BYTE(_val)				((u4Byte)(_val))
#endif

//
//	Example:
//		BIT_LEN_MASK_32(0) => 0x00000000
//		BIT_LEN_MASK_32(1) => 0x00000001
//		BIT_LEN_MASK_32(2) => 0x00000003
//		BIT_LEN_MASK_32(32) => 0xFFFFFFFF
//
#define BIT_LEN_MASK_32(__BitLen) \
	(0xFFFFFFFF >> (32 - (__BitLen)))
//
//	Example:
//		BIT_OFFSET_LEN_MASK_32(0, 2) => 0x00000003
//		BIT_OFFSET_LEN_MASK_32(16, 2) => 0x00030000
//
#define BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) \
	(BIT_LEN_MASK_32(__BitLen) << (__BitOffset)) 

//
//	Description:
//		Return 4-byte value in host byte ordering from
//		4-byte pointer in litten-endian system.
//
#define LE_P4BYTE_TO_HOST_4BYTE(__pStart) \
	(EF4Byte(*((UNALIGNED pu4Byte)(__pStart))))

//
//	Description:
//		Translate subfield (continuous bits in little-endian) of 4-byte value in litten byte to
//		4-byte value in host byte ordering.
//
#define LE_BITS_TO_4BYTE(__pStart, __BitOffset, __BitLen) \
	( \
		( LE_P4BYTE_TO_HOST_4BYTE(__pStart) >> (__BitOffset) ) \
		& \
		BIT_LEN_MASK_32(__BitLen) \
	)

//
//	Description:
//		Mask subfield (continuous bits in little-endian) of 4-byte value in litten byte oredering  
//		and return the result in 4-byte value in host byte ordering.
//
#define LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \
	( \
		LE_P4BYTE_TO_HOST_4BYTE(__pStart) \
		& \
		( ~BIT_OFFSET_LEN_MASK_32(__BitOffset, __BitLen) ) \
	)

//
//	Description:
//		Set subfield of little-endian 4-byte value to specified value.	
//
#define SET_BITS_TO_LE_4BYTE(__pStart, __BitOffset, __BitLen, __Value) \
	*((UNALIGNED pu4Byte)(__pStart)) = \
		EF4Byte( \
			LE_BITS_CLEARED_TO_4BYTE(__pStart, __BitOffset, __BitLen) \
			| \
			( (((u4Byte)__Value) & BIT_LEN_MASK_32(__BitLen)) << (__BitOffset) ) \
		);

		
#define BIT_LEN_MASK_16(__BitLen) \
		(0xFFFF >> (16 - (__BitLen)))
		
#define BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) \
	(BIT_LEN_MASK_16(__BitLen) << (__BitOffset))
	
#define LE_P2BYTE_TO_HOST_2BYTE(__pStart) \
	(EF2Byte(*((UNALIGNED pu2Byte)(__pStart))))
	
#define LE_BITS_TO_2BYTE(__pStart, __BitOffset, __BitLen) \
	( \
		( LE_P2BYTE_TO_HOST_2BYTE(__pStart) >> (__BitOffset) ) \
		& \
		BIT_LEN_MASK_16(__BitLen) \
	)
	
#define LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \
	( \
		LE_P2BYTE_TO_HOST_2BYTE(__pStart) \
		& \
		( ~BIT_OFFSET_LEN_MASK_16(__BitOffset, __BitLen) ) \
	)

#define SET_BITS_TO_LE_2BYTE(__pStart, __BitOffset, __BitLen, __Value) \
	*((UNALIGNED pu2Byte)(__pStart)) = \
		EF2Byte( \
			LE_BITS_CLEARED_TO_2BYTE(__pStart, __BitOffset, __BitLen) \
			| \
			( (((u2Byte)__Value) & BIT_LEN_MASK_16(__BitLen)) << (__BitOffset) ) \
		);
					
#define BIT_LEN_MASK_8(__BitLen) \
		(0xFF >> (8 - (__BitLen)))

#define BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) \
	(BIT_LEN_MASK_8(__BitLen) << (__BitOffset))

#define LE_P1BYTE_TO_HOST_1BYTE(__pStart) \
	(EF1Byte(*((pu1Byte)(__pStart))))

#define LE_BITS_TO_1BYTE(__pStart, __BitOffset, __BitLen) \
	( \
		( LE_P1BYTE_TO_HOST_1BYTE(__pStart) >> (__BitOffset) ) \
		& \
		BIT_LEN_MASK_8(__BitLen) \
	)

#define LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \
	( \
		LE_P1BYTE_TO_HOST_1BYTE(__pStart) \
		& \
		( ~BIT_OFFSET_LEN_MASK_8(__BitOffset, __BitLen) ) \
	)

#define SET_BITS_TO_LE_1BYTE(__pStart, __BitOffset, __BitLen, __Value) \
{ \
	*((pu1Byte)(__pStart)) = \
		EF1Byte( \
			LE_BITS_CLEARED_TO_1BYTE(__pStart, __BitOffset, __BitLen) \
			| \
			( (((u1Byte)__Value) & BIT_LEN_MASK_8(__BitLen)) << (__BitOffset) ) \
		); \
}

// Get the N-bytes aligment offset from the current length
#define	N_BYTE_ALIGMENT(__Value, __Aligment) ((__Aligment == 1) ? (__Value) : (((__Value + __Aligment - 1) / __Aligment) * __Aligment))

#endif // #ifndef __INC_ENDIANFREE_H
